/**
 * 深度克隆对象
 * @template T - 泛型类型参数
 * @param {T} obj - 需要克隆的对象，支持：普通对象、数组、Date、RegExp
 * @param {WeakMap<object, any>} [hash=new WeakMap()] - 用于处理循环引用的哈希表（内部使用）
 * @returns {T} 深度克隆后的新对象
 * @example
 * const original = { a: 1, b: { c: 2 } };
 * const cloned = deepClone(original);
 * console.log(cloned.b === original.b); // false
 *
 * @example 处理循环引用
 * const obj: any = { a: 1 };
 * obj.self = obj;
 * const cloned = deepClone(obj);
 * console.log(cloned.self === cloned); // true
 */
export function deepClone<T>(obj: T, hash = new WeakMap()): T {
  // 处理非对象类型
  if (obj === null || typeof obj !== 'object') return obj

  // 处理循环引用
  if (hash.has(obj)) return hash.get(obj)

  // 处理特殊对象类型
  switch (true) {
    case obj instanceof Date:
      return new Date(obj) as T
    case obj instanceof RegExp:
      return new RegExp(obj) as T
    case Array.isArray(obj):
      return obj.map(item => deepClone(item, hash)) as T
  }

  // 处理普通对象
  const cloneObj = Object.create(Object.getPrototypeOf(obj))
  hash.set(obj, cloneObj)

  for (const key of Reflect.ownKeys(obj)) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      cloneObj[key] = deepClone((obj as any)[key], hash)
    }
  }

  return cloneObj
}

/**
 * 深度合并对象
 * @template T - 目标对象类型
 * @template S - 源对象类型
 * @param {T} target - 目标对象
 * @param {S} source - 源对象
 * @returns {T & S} 合并后的新对象
 * @example
 * const merged = deepMerge({ a: 1 }, { b: 2 }); // { a: 1, b: 2 }
 * @example 处理数组合并
 * deepMerge({ arr: [1] }, { arr: [2] }); // { arr: [1, 2] }
 */
export function deepMerge<T extends object, S extends object>(target: T, source: S): T & S {
  const output = { ...target } as T & S

  for (const key of Object.keys(source) as Array<keyof S>) {
    const sourceValue = source[key]
    const targetValue = target[key as unknown as keyof T]

    if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
      ;(output as any)[key] = [...targetValue, ...sourceValue]
    } else if (
      sourceValue &&
      targetValue &&
      typeof sourceValue === 'object' &&
      typeof targetValue === 'object'
    ) {
      ;(output as any)[key] = deepMerge(targetValue, sourceValue)
    } else {
      ;(output as any)[key] = sourceValue ?? targetValue
    }
  }

  return output
}

/**
 * 浅层克隆对象
 * @template T - 泛型类型参数
 * @param {T} obj - 需要克隆的对象
 * @returns {T} 浅拷贝后的新对象
 * @example
 * const original = { a: 1, b: { c: 2 } };
 * const cloned = shallowClone(original);
 * console.log(cloned.b === original.b); // true
 *
 * @example 克隆数组
 * const arr = [1, [2, 3]];
 * const clonedArr = shallowClone(arr);
 * console.log(clonedArr[1] === arr[1]); // true
 */
export function shallowClone<T>(obj: T): T {
  if (obj === null || typeof obj !== 'object') return obj

  return Array.isArray(obj) ? ([...obj] as T) : ({ ...obj } as T)
}

/**
 * 选取对象指定属性
 * @template T - 原始对象类型
 * @template K - 选取的属性键
 * @param {T} obj - 原始对象
 * @param {K[]} keys - 需要保留的属性键数组
 * @returns {Pick<T, K>} 包含指定属性的新对象
 * @example
 * pick({ a: 1, b: 2 }, ['a']); // { a: 1 }
 */
export function filterObject(
  obj: Record<string, any>,
  keys: string[],
  strictMode: boolean = false,
): Record<string, any> {
  return keys.reduce(
    (acc, key) => {
      if (key in obj) {
        acc[key] = obj[key]
      }
      return acc
    },
    {} as Record<string, any>,
  )
}

/**
 * 排除对象指定属性
 * @template T - 原始对象类型
 * @template K - 排除的属性键
 * @param {T} obj - 原始对象
 * @param {K[]} keys - 需要排除的属性键数组
 * @returns {Omit<T, K>} 排除指定属性的新对象
 * @example
 * omit({ a: 1, b: 2 }, ['a']); // { b: 2 }
 */
export function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  return keys.reduce(
    (acc, key) => {
      if (key in obj) {
        acc[key] = obj[key]
      }
      return acc
    },
    {} as Pick<T, K>,
  )
}

export function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
  const validKeys = Object.keys(obj).filter(
    (key): key is string =>
      Object.prototype.hasOwnProperty.call(obj, key) && !keys.includes(key as K),
  )
  // 由于 validKeys 是 string[] 类型，而 pick 函数需要 (keyof T)[] 类型的参数，
  // 这里使用类型断言将 validKeys 转换为 (keyof T)[] 类型
  return pick(obj, validKeys as (keyof T)[])
}
